package handler

import (
	"context"
	"github.com/golang/protobuf/ptypes/empty"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	. "service/userop_srv/global"
	"service/userop_srv/model"
	"service/userop_srv/proto"
)

// 实现用户操作服务（service层）的接口
// 接口定义文件——userop.proto

type UseropServer struct{}

/*
MessageList(context.Context, *MessageRequest) (*MessageListResponse, error)
CreateMessage(context.Context, *MessageRequest) (*MessageResponse, error)
GetAddressList(context.Context, *AddressRequest) (*AddressListResponse, error)
CreateAddress(context.Context, *AddressRequest) (*AddressResponse, error)
DeleteAddress(context.Context, *AddressRequest) (*emptypb.Empty, error)
UpdateAddress(context.Context, *AddressRequest) (*emptypb.Empty, error)
GetFavList(context.Context, *UserFavRequest) (*UserFavListResponse, error)
AddUserFav(context.Context, *UserFavRequest) (*emptypb.Empty, error)
DeleteUserFav(context.Context, *UserFavRequest) (*emptypb.Empty, error)
GetUserFavDetail(context.Context, *UserFavRequest) (*emptypb.Empty, error)
*/

//获取用户的留言记录
func (g *UseropServer) MessageList(c context.Context, r *proto.MessageRequest) (*proto.MessageListResponse, error) {
	// 形参r中只有UserId是有效字段
	var messageList []*model.LeavingMessages
	res := DB.Where("user", r.UserId).Find(&messageList)
	if res.Error != nil {
		zap.S().Errorf("查询用户%d的留言列表失败: %v", r.UserId, res.Error)
		return nil, status.Errorf(codes.Internal, "查询用户%d的留言列表失败: %v", r.UserId, res.Error)
	}
	if res.RowsAffected == 0 {
		zap.S().Errorf("用户%d的留言列表为空", r.UserId)
		return nil, status.Errorf(codes.NotFound, "用户%d的留言列表为空", r.UserId)
	}
	messageListResponse := new(proto.MessageListResponse)
	messageListResponse.Total = int32(res.RowsAffected)
	for _, m := range messageList {
		messageListResponse.Data = append(messageListResponse.Data, &proto.MessageResponse{
			Id:          m.ID,
			UserId:      m.User,
			MessageType: m.MessageType,
			Subject:     m.Subject,
			Message:     m.Message,
			File:        m.File,
		})
	}
	return messageListResponse, nil
}

// 创建留言记录
func (g *UseropServer) CreateMessage(c context.Context, r *proto.MessageRequest) (*proto.MessageResponse, error) {
	m := &model.LeavingMessages{
		User:        r.UserId,
		MessageType: r.MessageType,
		Subject:     r.Subject,
		Message:     r.Message,
		File:        r.File,
	}

	tx := DB.Begin()
	result := tx.Create(m)
	if result.Error != nil {
		tx.Rollback()
		zap.S().Error("创建留言记录失败: ", result.Error)
		return nil, status.Errorf(codes.Internal, "创建留言记录失败: %v", result.Error)
	}
	tx.Commit()

	return &proto.MessageResponse{
		Id: m.ID,
	}, nil
}

// 获取用户的收货地址列表
func (g *UseropServer) GetAddressList(c context.Context, r *proto.AddressRequest) (*proto.AddressListResponse, error) {
	// 形参r中只有UserId是有效字段
	var addressList []*model.Address
	res := DB.Where("user", r.UserId).Find(&addressList)
	if res.Error != nil {
		zap.S().Errorf("查询用户%d的收货地址列表失败: %v", r.UserId, res.Error)
		return nil, status.Errorf(codes.Internal, "查询用户%d的收货地址列表失败: %v", r.UserId, res.Error)
	}
	if res.RowsAffected == 0 {
		zap.S().Errorf("用户%d的收货地址列表为空", r.UserId)
		return nil, status.Errorf(codes.NotFound, "用户%d的收货地址列表为空", r.UserId)
	}

	addressListResponse := new(proto.AddressListResponse)
	addressListResponse.Total = int32(res.RowsAffected)
	for _, address := range addressList {
		addressListResponse.Data = append(addressListResponse.Data, &proto.AddressResponse{
			Id:           address.ID,
			UserId:       address.User,
			Province:     address.Province,
			City:         address.City,
			District:     address.District,
			Address:      address.Address,
			SignerName:   address.SignerName,
			SignerMobile: address.SignerMobile,
		})
	}
	return addressListResponse, nil
}

// 用户添加收货地址
func (g *UseropServer) CreateAddress(c context.Context, r *proto.AddressRequest) (*proto.AddressResponse, error) {
	address := &model.Address{
		User:         r.UserId,
		Province:     r.Province,
		City:         r.City,
		District:     r.District,
		Address:      r.Address,
		SignerName:   r.SignerName,
		SignerMobile: r.SignerMobile,
	}

	tx := DB.Begin()
	result := tx.Create(address)
	if result.Error != nil {
		tx.Rollback()
		zap.S().Error("添加收货地址失败: ", result.Error)
		return nil, status.Errorf(codes.Internal, "添加收货地址失败: %v", result.Error)
	}
	tx.Commit()

	return &proto.AddressResponse{
		Id: address.ID,
	}, nil
}

// 用户删除收货地址
func (g *UseropServer) DeleteAddress(c context.Context, r *proto.AddressRequest) (*emptypb.Empty, error) {
	// 针对这个接口而言，r中只有Id是有效字段
	address := new(model.Address)
	address.ID = r.Id

	result := DB.Where(address).First(address)
	if result.RowsAffected != 1 {
		zap.S().Errorf("id为%d的收货地址不存在", r.Id)
		return nil, status.Errorf(codes.NotFound, "id为%d的收货地址不存在", r.Id)
	}

	result = DB.Delete(address)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &empty.Empty{}, nil
}

// 用户修改收货地址
func (g *UseropServer) UpdateAddress(c context.Context, r *proto.AddressRequest) (*emptypb.Empty, error) {
	// 形参r中除了UserID，都是有效字段
	address := new(model.Address)
	address.ID = r.Id
	if res := DB.First(address); res.RowsAffected == 0 {
		zap.S().Error("id为%d的收货地址不存在", r.Id)
		return nil, status.Errorf(codes.Internal, "id为%d的收货地址不存在", r.Id)
	}

	address.Province = r.Province
	address.City = r.City
	address.District = r.District
	address.Address = r.Address
	address.SignerName = r.SignerName
	address.SignerMobile = r.SignerMobile

	tx := DB.Begin()
	rsp := tx.Save(address)
	if rsp.Error != nil {
		tx.Rollback()
		zap.S().Errorf("id为%d的收货地址修改失败:%v", r.Id, rsp.Error)
		return nil, status.Errorf(codes.Internal, "id为%d的收货地址修改失败", r.Id)
	}
	tx.Commit()

	return &emptypb.Empty{}, nil
}

// 获取用户的收藏列表
func (g *UseropServer) GetFavList(c context.Context, r *proto.UserFavRequest) (*proto.UserFavListResponse, error) {
	var favList []*model.UserFav
	// 既可以查询某一用户的收藏列表，又可以查询某一商品被哪些用户收藏过
	res := DB.Where(&model.UserFav{User: r.UserId, Goods: r.GoodsId}).Find(&favList)
	if res.Error != nil {
		zap.S().Errorf("查询收藏列表失败")
		return nil, status.Errorf(codes.Internal, "查询收藏列表失败: %v", res.Error)
	}
	if res.RowsAffected == 0 {
		zap.S().Error("符合条件的收藏列表为空")
		return nil, status.Errorf(codes.NotFound, "符合条件的收藏列表为空")
	}

	userFavListResponse := new(proto.UserFavListResponse)
	userFavListResponse.Total = int32(res.RowsAffected)
	for _, fav := range favList {
		userFavListResponse.Data = append(userFavListResponse.Data, &proto.UserFavResponse{
			UserId:  fav.User,
			GoodsId: fav.Goods,
		})
	}
	return userFavListResponse, nil
}

// 用户将商品添加至"我的收藏"
func (g *UseropServer) AddUserFav(c context.Context, r *proto.UserFavRequest) (*emptypb.Empty, error) {
	userFav := &model.UserFav{
		User:  r.UserId,
		Goods: r.GoodsId,
	}

	if res := DB.Where(userFav).First(userFav); res.RowsAffected == 1 {
		zap.S().Errorf("用户%d已收藏过商品%d", r.UserId, r.GoodsId)
		return nil, status.Errorf(codes.AlreadyExists, "用户%d已收藏过商品%d", r.UserId, r.GoodsId)
	}

	tx := DB.Begin()
	result := tx.Create(userFav)
	if result.Error != nil {
		tx.Rollback()
		zap.S().Errorf("用户%d收藏商品%d失败：%v", r.UserId, r.GoodsId, result.Error)
		return nil, status.Errorf(codes.Internal, "用户%d收藏商品%d失败：%v", r.UserId, r.GoodsId, result.Error)
	}
	tx.Commit()

	return &emptypb.Empty{}, nil
}

// 删除用户的收藏记录
func (g *UseropServer) DeleteUserFav(c context.Context, r *proto.UserFavRequest) (*emptypb.Empty, error) {
	userFav := &model.UserFav{
		User:  r.UserId,
		Goods: r.GoodsId,
	}

	if res := DB.Where(userFav).First(userFav); res.RowsAffected == 0 {
		zap.S().Errorf("用户%d的收藏记录中没有商品%d", r.UserId, r.GoodsId)
		return nil, status.Errorf(codes.NotFound, "用户%d的收藏记录中没有商品%d", r.UserId, r.GoodsId)
	}

	result := DB.Delete(userFav)
	if result.Error != nil {
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &empty.Empty{}, nil
}

// 判断用户是否收藏过特定商品
func (g *UseropServer) GetUserFavDetail(c context.Context, r *proto.UserFavRequest) (*emptypb.Empty, error) {
	userFav := &model.UserFav{
		User:  r.UserId,
		Goods: r.GoodsId,
	}

	if res := DB.Where(userFav).First(userFav); res.RowsAffected == 0 {
		zap.S().Errorf("用户%d未收藏过商品%d", r.UserId, r.GoodsId)
		return nil, status.Errorf(codes.NotFound, "用户%d未收藏过商品%d", r.UserId, r.GoodsId)
	}

	// err若为空则说明用户已收藏过该商品
	return &emptypb.Empty{}, nil
}
